#include <QDebug>

#include "metronomo.h"
#include "matematicas.h"

Metronomo::Metronomo()
{
    tempo = 120;
    pulsosPorCompas = 4;
	activo = false;
	reproducirSonido = false;

	milisegundosAcumulados = 0;	
    compasesAcumulados = 0;

    milisegundosPorCompas = 0;
    milisegundosPorPulso = 0;

    ultimoPulsoEjecutado = -1;

	sonido1 = new QSound("../sonidos/metronomo1.wav");
	sonido2 = new QSound("../sonidos/metronomo2.wav");
}

Metronomo::~Metronomo()
{
	delete sonido1;
	delete sonido2;
}

void Metronomo::setTempo(int tempo)
{
    this->tempo = tempo;
    if (activo) {
        compasesAcumulados = getNumeroCompasActual();
        milisegundosAcumulados += contadorTiempo.getMilisegundosTranscurridos();
        contadorTiempo.inicializar();
        ultimoPulsoEjecutado = -1;
        actualizar();
    }
}

double Metronomo::getMilisegundoNota(const NotaCompas& nota, int numeroCompas)
{
	double milisegundosPorDivision = milisegundosPorPulso / nota.getDivisiones();

    int diferenciaCompases = numeroCompas - compasesAcumulados;

	double msNota = 
		diferenciaCompases * milisegundosPorCompas +
		nota.getPulso() * milisegundosPorPulso +
		nota.getDivision() * milisegundosPorDivision;

    return milisegundosAcumulados + msNota;
}

double Metronomo::distanciaNota(const NotaCompas& nota, int numeroCompas)
{
    double msNota = getMilisegundoNota(nota, numeroCompas);
    double msActual = getMilisegundosDesdeInicio();

	double diferenciaMilisegundos = msNota - msActual;
    return diferenciaMilisegundos;
}

void Metronomo::arrancar()
{	
	actualizar();
    compasesAcumulados = 0;
    contadorTiempo.inicializar();	
	ultimoPulsoEjecutado = -1;
    activo = true;
}

void Metronomo::parar()
{
    activo = false;
}

void Metronomo::actualizar()
{	
	milisegundosPorPulso = 60000 / tempo;
	milisegundosPorCompas = milisegundosPorPulso * pulsosPorCompas;
}

quint64 Metronomo::getMilisegundosDesdeInicio() 
{
    return activo ? milisegundosAcumulados + contadorTiempo.getMilisegundosTranscurridos() : 0;
}

int Metronomo::getNumeroCompasActual()
{
    if (!activo || milisegundosPorPulso == 0) {
        return 0;
    }

    double msActual = contadorTiempo.getMilisegundosTranscurridos();
    int numeroCompases = floor(msActual / milisegundosPorCompas);
    return compasesAcumulados + numeroCompases;
}

double Metronomo::getProporcionCompletadoCompas()
{
	if (!activo || milisegundosPorCompas == 0 || milisegundosPorPulso == 0) {
		return 0;
	}
	double msActual = contadorTiempo.getMilisegundosTranscurridos();

	double numeroCompasActual = floor(msActual / milisegundosPorCompas);

	double resto = msActual - milisegundosPorCompas * numeroCompasActual;

	return resto / milisegundosPorCompas;
}

quint64 Metronomo::getMilisegundoInicioCompas()
{
	double msActual = milisegundosAcumulados + contadorTiempo.getMilisegundosTranscurridos();

	int numeroCompasActual = getNumeroCompasActual() - compasesAcumulados;

	return milisegundosAcumulados + numeroCompasActual * milisegundosPorCompas;
}

#define MILISEGUNDOS_ERROR 10

void Metronomo::comprobarSonido()
{
	if (!reproducirSonido) {
		return;
	}

	double msActual = contadorTiempo.getMilisegundosTranscurridos();

	int numeroPulsoCercano = floor(msActual / milisegundosPorPulso);

	if (numeroPulsoCercano <= ultimoPulsoEjecutado) {
		numeroPulsoCercano++;
	}

	if (numeroPulsoCercano <= ultimoPulsoEjecutado) {
		return;
	}

	if (fabs(numeroPulsoCercano * milisegundosPorPulso - msActual) > MILISEGUNDOS_ERROR) {
		return;
	}

	bool esInicioCompas = numeroPulsoCercano % pulsosPorCompas == 0;

	if (esInicioCompas) {
		sonido1->play();
	} else {
		sonido2->play();
	}
	ultimoPulsoEjecutado = numeroPulsoCercano;


}